// XomParser.groovy
// Mac Radigan
// $Id: XomParserImpl.groovy 40 2011-10-23 09:01:42Z mac.radigan $
package org.radigan.xom.impl

import org.radigan.xom.service.Xom
import org.radigan.xom.service.XomException
import org.radigan.xom.service.AstNode

import org.xml.sax.helpers.XMLReaderAdapter
import org.xml.sax.Attributes
import org.xml.sax.SAXException
import org.xml.sax.SAXParseException
import org.xml.sax.helpers.DefaultHandler
import javax.xml.validation.TypeInfoProvider
import org.apache.xerces.xs.PSVIProvider
//import org.apache.xerces.xs.ElementPSVI
//import org.apache.xerces.xs.XSModel
import org.w3c.dom.TypeInfo
import java.net.URI
import java.util.Stack

public class XomParserImpl extends DefaultHandler {

   private static final String XINCLUDE_NS = "http://www.w3.org/2001/XInclude"
   private static final String ANON_PREFIX = "#AnonType_"
   private StringBuffer characterBuffer = null
   private AstNode root = null
   private AstNode cursor = null
   private AstNode current = null
   private TypeInfoProvider typeInfoProvider = null
   private XomImpl xom = null
   //private PSVIProvider psviProvider = null

   private void initialize() {
     //characterBuffer = new StringBuffer()
   }

   public XomParserImpl(Xom xom) throws SAXException {
     this.xom = xom
     initialize()
   }
         
   public XomParserImpl(TypeInfoProvider typeInfoProvider) throws SAXException {
     this.typeInfoProvider = typeInfoProvider
     initialize()
   }

   //public XomParserImpl() throws SAXException {
   //  initialize()
   //}

   public void setTypeInfoProvider(TypeInfoProvider typeInfoProvider) throws SAXException {
     this.typeInfoProvider = typeInfoProvider
   }

   //public void setPsviProvider(PSVIProvider psviProvider) throws SAXException {
   //  this.psviProvider = psviProvider
   //}

   public AstNode getAbstractSyntaxTree() throws XomException {
     return root.getChildAt(0)
   }

   public void startDocument() throws SAXException {
   }

   public void startElement(String namespace, String localName,String qName, Attributes attributes) throws SAXException {
      if(XINCLUDE_NS==namespace) {
        println "XInclude encountered..."
        def xiXom = new XomImpl()
        def xiFilename = attributes.getValue(XINCLUDE_NS, "href")
        def xiFile = new File(xiFilename)
        xiXom.read(xom.resolveFile(xiFile))
        current = xiXom.getAbstractSyntaxTree()
        cursor.add(current)
      } else {
        characterBuffer = new StringBuffer()
        def namespaceUri = new URI(namespace) 
        def typeName = typeInfoProvider.getElementTypeInfo().getTypeName()
        def typeNamespace = typeInfoProvider.getElementTypeInfo().getTypeNamespace()
        def typeNamespaceUri = new URI(typeNamespace)
        current = new AstNodeImpl(namespaceUri, typeName, localName, null)
        if(!cursor) {
          root = new AstNodeImpl(new URI("ROOT"), "ROOT", "ROOT", null)
          root.add(current)
        } else {
          cursor.add(current)
        }
      }
      cursor = current
   }

   public void endElement(String namespace, String localName, String qName) throws SAXException {
     if(cursor) {
       if(!cursor.getType().startsWith(ANON_PREFIX) || cursor.getType()[0]==cursor.getType()[0].toUpperCase()) {
         cursor.setValue(characterBuffer.toString())
       }
       cursor = cursor.getParent()
     }
   }

   public void characters(char[] ch, int start, int length) throws SAXException {
     characterBuffer.append(ch, start, length)
   }

  private void xomPrint(SAXParseException exception) {
    def publicId = exception.getPublicId()
    def systemId = exception.getSystemId()
    def lineNumber = new Integer(exception.getLineNumber())
    def columnNumber = new Integer(exception.getColumnNumber())
    def message = exception.getMessage()
    println "line ${lineNumber} column ${columnNumber}:  ${message}"
  }

  public void warning(SAXParseException exception) {
    xomPrint(exception)
  }

   public void error(SAXParseException exception) {
     xomPrint(exception)
   }

   public void fatalError(SAXParseException exception) throws SAXParseException {
     xomPrint(x)
     throw exception
   }

}


// *EOF*
